using Microsoft.Extensions.Caching.Distributed;
using StackExchange.Redis;
using System.Text.Json;

namespace WeatherSystem.API.Services
{
    /// <summary>
    /// 缓存服务实现
    /// </summary>
    public class CacheService : ICacheService
    {
        private readonly IDistributedCache _distributedCache;
        private readonly IConnectionMultiplexer? _redis;
        private readonly ILogger<CacheService> _logger;
        private readonly JsonSerializerOptions _jsonOptions;

        public CacheService(
            IDistributedCache distributedCache,
            ILogger<CacheService> logger,
            IConnectionMultiplexer? redis = null)
        {
            _distributedCache = distributedCache;
            _redis = redis;
            _logger = logger;
            _jsonOptions = new JsonSerializerOptions
            {
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                WriteIndented = false
            };
        }

        public async Task<T?> GetAsync<T>(string key) where T : class
        {
            try
            {
                var value = await _distributedCache.GetStringAsync(key);
                if (string.IsNullOrEmpty(value))
                {
                    return null;
                }

                return JsonSerializer.Deserialize<T>(value, _jsonOptions);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "缓存获取失败，键: {Key}", key);
                return null;
            }
        }

        public async Task SetAsync<T>(string key, T value, TimeSpan? expiration = null) where T : class
        {
            try
            {
                var serializedValue = JsonSerializer.Serialize(value, _jsonOptions);
                var options = new DistributedCacheEntryOptions();

                if (expiration.HasValue)
                {
                    options.AbsoluteExpirationRelativeToNow = expiration.Value;
                }
                else
                {
                    // 默认缓存15分钟
                    options.AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(15);
                }

                await _distributedCache.SetStringAsync(key, serializedValue, options);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "缓存设置失败，键: {Key}", key);
            }
        }

        public async Task RemoveAsync(string key)
        {
            try
            {
                await _distributedCache.RemoveAsync(key);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "缓存删除失败，键: {Key}", key);
            }
        }

        public async Task RemovePatternAsync(string pattern)
        {
            try
            {
                if (_redis != null)
                {
                    var database = _redis.GetDatabase();
                    var server = _redis.GetServer(_redis.GetEndPoints().First());
                    
                    await foreach (var key in server.KeysAsync(pattern: pattern))
                    {
                        await database.KeyDeleteAsync(key);
                    }
                }
                else
                {
                    _logger.LogWarning("Redis未配置，无法执行模式删除操作");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "缓存模式删除失败，模式: {Pattern}", pattern);
            }
        }

        public async Task<bool> ExistsAsync(string key)
        {
            try
            {
                var value = await _distributedCache.GetStringAsync(key);
                return !string.IsNullOrEmpty(value);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "缓存存在性检查失败，键: {Key}", key);
                return false;
            }
        }

        public async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> getItem, TimeSpan? expiration = null) where T : class
        {
            try
            {
                var cachedValue = await GetAsync<T>(key);
                if (cachedValue != null)
                {
                    return cachedValue;
                }

                var item = await getItem();
                if (item != null)
                {
                    await SetAsync(key, item, expiration);
                }

                return item;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "GetOrSet缓存操作失败，键: {Key}", key);
                // 如果缓存失败，直接返回数据
                return await getItem();
            }
        }

        public async Task RemoveByPrefixAsync(string prefix, CancellationToken cancellationToken = default)
        {
            try
            {
                await RemovePatternAsync($"{prefix}*");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "缓存前缀删除失败，前缀: {Prefix}", prefix);
            }
        }

        public async Task ClearAsync(CancellationToken cancellationToken = default)
        {
            try
            {
                if (_redis != null)
                {
                    var database = _redis.GetDatabase();
                    var server = _redis.GetServer(_redis.GetEndPoints().First());

                    await foreach (var key in server.KeysAsync())
                    {
                        await database.KeyDeleteAsync(key);
                    }
                }
                else
                {
                    _logger.LogWarning("Redis未配置，无法执行清空操作");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "缓存清空失败");
            }
        }
    }
}